package com.naiterui.ehp.bs.doctor.service.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.naiterui.common.repository.page.CustomizedPageConvertor;
import com.naiterui.common.repository.page.Page;
import com.naiterui.common.repository.page.PageVO;
import com.naiterui.ehp.bp.bo.HeaderParams;
import com.naiterui.ehp.bp.domain.Department;
import com.naiterui.ehp.bp.domain.Doctor;
import com.naiterui.ehp.bp.domain.DrPatientRemarkname;
import com.naiterui.ehp.bp.domain.Hospital;
import com.naiterui.ehp.bp.domain.Patient;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.utils.biz.TitleUtil;
import com.naiterui.ehp.bp.utils.date.DateUtil;
import com.naiterui.ehp.bp.utils.lang.ConfigUtil;
import com.naiterui.ehp.bp.utils.lang.StringUtil;
import com.naiterui.ehp.bp.utils.net.RestHttpUtil;
import com.naiterui.ehp.bs.doctor.dao.IDepartmentDao;
import com.naiterui.ehp.bs.doctor.dao.IDoctorDao;
import com.naiterui.ehp.bs.doctor.dao.IDrPatientGroupDetailDao;
import com.naiterui.ehp.bs.doctor.dao.IHospitalDao;
import com.naiterui.ehp.bs.doctor.dao.IPatientDao;
import com.naiterui.ehp.bs.doctor.dao.IPatientGroupDao;
import com.naiterui.ehp.bs.doctor.dao.mongo.AdDrBatchMessageDao;
import com.naiterui.ehp.bs.doctor.exception.ExceptionCodes;
import com.naiterui.ehp.bs.doctor.prodocl.DrBatchMessage;
import com.naiterui.ehp.bs.doctor.prodocl.Education;
import com.naiterui.ehp.bs.doctor.prodocl.Message;
import com.naiterui.ehp.bs.doctor.prodocl.ReceiveInfo;
import com.naiterui.ehp.bs.doctor.service.IDrBatchMessageService;
import com.naiterui.ehp.bs.doctor.service.IDrPatientRemarkService;
import com.naiterui.ehp.bs.doctor.service.IPatientGroupService;
import com.naiterui.ehp.bs.doctor.utils.LimitValueConfig;
import com.naiterui.ehp.bs.doctor.utils.PatientUtil;
import com.naiterui.ehp.bs.doctor.utils.PropertyValueConstants;
import com.naiterui.ehp.bs.doctor.utils.message.Constants;
import com.naiterui.ehp.bs.doctor.utils.message.IMessageTransCoder;
import com.naiterui.ehp.bs.doctor.vo.BaseDrSendInfoVo;
import com.naiterui.ehp.bs.doctor.vo.BatchMessageVo;
import com.naiterui.ehp.bs.doctor.vo.DoctorVO;
import com.naiterui.ehp.bs.doctor.vo.LimitConfigVO;
import com.naiterui.ehp.bs.doctor.vo.PatientGroupVo;
import com.naiterui.ehp.bs.doctor.vo.SendInfoVo;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
@AllArgsConstructor
public class AdDrBatchMessageServiceImpl implements IDrBatchMessageService {

    private static final String BATCH_MESSAGE_SEND_URL = ConfigUtil.getString(PropertyValueConstants.BATCH_MESSAGE_SEND_URL);

    private AdDrBatchMessageDao adDrBatchMessageDao;
    private IPatientDao patientDao;
    private IMessageTransCoder messageTransCoder;
    private IDoctorDao doctorDao;
    private IDepartmentDao departmentDao;
    private IHospitalDao hospitalDao;
    private IPatientGroupService patientGroupService;
    private IPatientGroupDao patientGroupDao;
    private IDrPatientRemarkService drPatientRemarkNameService;
    private IDrPatientGroupDetailDao drPatientGroupDetailDao;

    /**
     * 获取群发信息
     */
    @Override
    public SendInfoVo getSendInfo(Long doctorId) throws BusinessException {
        String totalNum = ConfigUtil.getString(PropertyValueConstants.BATHC_MEESAGE_TOTAL_NUM);
        if (StringUtils.isBlank(totalNum)) {
            log.error("  params exception totalNum：{},", totalNum);
            throw new BusinessException(ExceptionCodes.PARAM_ERROR);
        }
        Long num = this.adDrBatchMessageDao.getCountDrBathcMessage(doctorId);
        SendInfoVo sendInfoVo = new SendInfoVo();
        sendInfoVo.setCurrentTime(System.currentTimeMillis());
        sendInfoVo.setLastNum(Long.parseLong(totalNum) - num);
        sendInfoVo.setTotalNum(Long.parseLong(totalNum));
        return sendInfoVo;
    }

    /**
     * 获取群发次数
     */
    @Override
    public BaseDrSendInfoVo getCountNum(Long doctorId) throws BusinessException {
        String totalNum = ConfigUtil.getString(PropertyValueConstants.BATHC_MEESAGE_TOTAL_NUM);
        if (StringUtils.isBlank(totalNum)) {
            log.error("  params exception totalNum：{}", totalNum);
            throw new BusinessException(ExceptionCodes.PARAM_ERROR);
        }
        Long num = this.adDrBatchMessageDao.getCountDrBathcMessage(doctorId);
        BaseDrSendInfoVo sendInfoVo = new BaseDrSendInfoVo();
        sendInfoVo.setLastNum(Long.parseLong(totalNum) - num);
        sendInfoVo.setTotalNum(Long.parseLong(totalNum));
        return sendInfoVo;
    }

    /**
     * 确认发送
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addBatchMessage(Long doctorId, String message, HeaderParams headerParams, ReceiveInfo receiveInfo) throws BusinessException {
        LimitConfigVO limitConfigVO = LimitValueConfig.parseLimitConfig(ConfigUtil.getString(LimitValueConfig.LIMIT_BATCHMESSAGECONTENT));
        Message<?> messageObj = this.messageTransCoder.decodeMessage(message);
        String content;
        // 文本消息则判断内容长度
        if (messageObj.getType() == Constants.MESSAGE_TYPE_TEXT) {
            content = (String) messageObj.getContent();
            if (StringUtils.isBlank(content)) {
                throw new BusinessException(ExceptionCodes.BATCH_MESSAGE_CONTENT_IS_NULL);
            }
            Integer max = limitConfigVO.getMax();
            if (content.length() > max) {
                throw new BusinessException(ExceptionCodes.PARAM_ERROR);
            }
        }

        // 判断群发次数
        BaseDrSendInfoVo baseDrSendInfoVo = this.getCountNum(doctorId);
        if (baseDrSendInfoVo.getLastNum().intValue() <= 0) {
            throw new BusinessException(ExceptionCodes.BATCH_MESSAGE_SENDTIMES_EXCEEDED);
        }

        String tempPatientIds = receiveInfo.getPatientIds();
        // 去掉末尾逗号
        if (!StringUtils.isBlank(tempPatientIds) && tempPatientIds.lastIndexOf(",") == (tempPatientIds.length() - 1)) {
            tempPatientIds = tempPatientIds.substring(0, tempPatientIds.length() - 1);
        }

        // 获取收件人
        String patientIds = this.getPatientIds(receiveInfo.getReceiveType(), doctorId, receiveInfo.getGroupIds(), tempPatientIds);
        if (StringUtils.isBlank(patientIds)) {
            throw new BusinessException(ExceptionCodes.BATCH_MESSAGE_PATIENT_IS_NULL);
        }

        String groupNames = "";
        String groupIds = receiveInfo.getGroupIds();
        if (StringUtils.isNotBlank(groupIds)) {
            if (groupIds.endsWith(",")) {
                groupIds = groupIds.substring(0, groupIds.length() - 1);
            }
            List<String> groupNameList = this.patientGroupDao.findPatientGroupNameList(groupIds);
            groupNames = this.listForStr(groupNameList);

        }

        String patientNames = "";
        if (receiveInfo.getReceiveType() == ReceiveInfo.DEFINED) {
            patientNames = this.getPatientNames(doctorId, patientIds);
        }

        Date date = new Date();
        DrBatchMessage drBatchMessage = new DrBatchMessage();
        drBatchMessage.setMessage(message);
        drBatchMessage.setDoctorId(doctorId);
        drBatchMessage.setPatientIds(patientIds);
        drBatchMessage.setGroupIds(groupIds);
        drBatchMessage.setReceiveType(receiveInfo.getReceiveType());
        drBatchMessage.setStatus(DrBatchMessage.STATUS_NON_REMOVE);
        drBatchMessage.setCreatedAt(date);
        drBatchMessage.setTimeStamp(date.getTime());
        drBatchMessage.setGroupNames(groupNames);
        drBatchMessage.setPatientNames(patientNames);
        this.adDrBatchMessageDao.save(drBatchMessage);

        // 发送消息
        String header = JSON.toJSONString(headerParams);
        this.send(message, header, patientIds, drBatchMessage.getId());

    }

    /**
     * 群发消息列表
     */
    @Override
    public PageVO<BatchMessageVo> getList(Long doctorId, int pageNo, int pageSize) throws BusinessException {

        PageVO<DrBatchMessage> pagedList = this.getDrBatchMessageList(doctorId, pageNo, pageSize);
        List<DrBatchMessage> templetList = pagedList.getResult();
        List<BatchMessageVo> templetVOList = new ArrayList<>();
        DoctorVO doctorVO = this.buildDoctorVo(doctorId);
        if (templetList != null && templetList.size() > 0) {
            for (DrBatchMessage drBatchMessage : templetList) {
                BatchMessageVo templetVO = new BatchMessageVo();
                templetVO.setId(drBatchMessage.getId());
                templetVO.setCreatedAt(DateUtil.formatDate(drBatchMessage.getCreatedAt(), DateUtil.MONTH_DAY_HH_DD_FORMAT));
                templetVO.setName(doctorVO.getName());
                templetVO.setDepartment(doctorVO.getDepartment());
                templetVO.setHospital(doctorVO.getHospital());
                templetVO.setTitle(doctorVO.getTitle());
                Message<?> message = this.messageTransCoder.decodeMessage(drBatchMessage.getMessage());
                if (message.getType() == Constants.MESSAGE_TYPE_TEXT) {
                    templetVO.setContent((String) message.getContent());
                } else if (message.getType() == Constants.MESSAGE_TYPE_EDU) {
                    Education education = (Education) message.getContent();
                    templetVO.setEduId(education.getEduId());
                    templetVO.setEduTitle(education.getEduTitle());
                    templetVO.setEduUrl(education.getEduUrl());
                    templetVO.setContent(education.getText());
                }

                String groupIds = drBatchMessage.getGroupIds();
                String patientIds = drBatchMessage.getPatientIds();
                String patientNames = drBatchMessage.getPatientNames();
                Integer receiveType = drBatchMessage.getReceiveType();
                String recipients = this.getMsgRecipients(receiveType, drBatchMessage.getGroupNames(), patientNames);
                templetVO.setRecipients(recipients);
                templetVO.setReceiveType(receiveType);
                templetVO.setGroupIds(groupIds);
                templetVO.setPatientIds(patientIds);
                templetVOList.add(templetVO);
            }
        }
        return CustomizedPageConvertor.buildPageVOWithCustom(pagedList.getPageNo(), pagedList.getPageSize(), templetVOList,
                                                             pagedList.getTotalCount());
    }

    /**
     * 删除群发消息
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(Long doctorId, String id) throws BusinessException {

        DrBatchMessage drBatchMessage = this.adDrBatchMessageDao.getDrBatchMessageById(id);
        if (drBatchMessage == null || drBatchMessage.getDoctorId().intValue() != doctorId.intValue()) {
            throw new BusinessException(ExceptionCodes.PARAM_ERROR);
        }
        drBatchMessage.setStatus(DrBatchMessage.STATUS_REMOVE);
        this.adDrBatchMessageDao.update(drBatchMessage);

    }

    /**
     * 消息删除任务
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteTask() {
        List<DrBatchMessage> list = this.adDrBatchMessageDao.findDrBatchMessageByMonth();
        for (DrBatchMessage drBatchMessage : list) {
            drBatchMessage.setStatus(DrBatchMessage.STATUS_REMOVE);
            this.adDrBatchMessageDao.update(drBatchMessage);
        }
    }

    /**
     * 获取医生分组列表
     */
    @Override
    public List<PatientGroupVo> findPatientGroupByDoctorId(Long doctorId) {
        return this.patientGroupService.findPatientGroupByDoctorId(doctorId, true);
    }

    /**
     * 构建医生信息
     */
    private DoctorVO buildDoctorVo(Long doctorId) {
        Doctor doctor = this.doctorDao.get(doctorId);
        String name = doctor.getName();
        String title = TitleUtil.getTitle(doctor.getTitleId());
        String department = "";
        if (doctor.getDepartmentId() != null) {
            if (doctor.getDepartmentId() == 0) {
                department = doctor.getCustomDepartment();
            } else {
                Department departmentObj = this.departmentDao.get(doctor.getDepartmentId());
                if (departmentObj != null) {
                    department = departmentObj.getName();
                }
            }
        }
        String hospital = "";
        if (doctor.getHospitalId() != null) {
            if (doctor.getHospitalId().equals(0)) {
                hospital = doctor.getHospitalName();
            } else {
                Hospital hospitalObj = this.hospitalDao.get(doctor.getHospitalId());
                if (hospitalObj != null) {
                    hospital = hospitalObj.getName();
                }
            }

        }
        DoctorVO doctorVO = new DoctorVO();
        doctorVO.setDepartment(department);
        doctorVO.setName(name);
        doctorVO.setHospital(hospital);
        doctorVO.setTitle(title);
        return doctorVO;
    }

    /**
     * 群发历史记录
     */
    private PageVO<DrBatchMessage> getDrBatchMessageList(Long doctorId, int pageNo, int pageSize) {

        // 排序条件
        String orderBy = Page.DESC;

        // 查询出当页数据
        List<DrBatchMessage> result = this.adDrBatchMessageDao.getDrBatchMessageList(doctorId, pageNo, pageSize);

        // 查询出总条数
        long totalCount = this.adDrBatchMessageDao.queryCount(doctorId);

        return CustomizedPageConvertor.buildPageVOWithCustom(pageNo, pageSize, result, (int) totalCount, orderBy);

    }

    /**
     * 发送群消息
     */
    private void send(String message, String header, String patientIds, String batchId) {
        try {
            log.debug("-- send batch message url：{}", BATCH_MESSAGE_SEND_URL);
            Map<String, String> params = new HashMap<>();
            params.put("message", message);
            params.put("header", header);
            params.put("toIds", patientIds);
            params.put("batchId", batchId);
            log.debug("-- send batch message  message:{},toIds:{},header:{}", message, patientIds, header);
            RestHttpUtil.post().url(BATCH_MESSAGE_SEND_URL).paramMap(params).asyncExecuteData();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * 获取群发的患者列表
     */
    private String getPatientIds(Integer receiveType, Long doctorId, String groupIds, String patientIds) {
        String list = "";
        // 全部患者
        if (receiveType == ReceiveInfo.ALL) {
            List<Long> patientList = this.patientDao.findPatientList(doctorId);
            list = this.listForStr(patientList);
        }
        // 组患者
        else if (receiveType == ReceiveInfo.GROUP) {
            Set<Long> patientSet = this.getAllGroupPatient(groupIds);
            list = this.listForStr(patientSet);
        }
        // 组患者取反
        else if (receiveType == ReceiveInfo.GROUP_REVERSE) {
            Set<Long> patientSet = this.getAllGroupPatient(groupIds);
            list = this.listForStr(patientSet);
            if (StringUtils.isBlank(list)) {
                List<Long> patientList = this.patientDao.findPatientList(doctorId);
                list = this.listForStr(patientList);
            } else {
                List<Long> patientList = this.patientDao.findPatientList(doctorId);
                patientList.removeAll(patientSet);
                list = this.listForStr(patientList);
            }
        }
        // 自定义患者
        else if (receiveType == ReceiveInfo.DEFINED) {
            List<Long> ids = StringUtil.convertLongStr2List(patientIds, ",");
            List<?> patientList = this.patientDao.findPatientIdList(this.listForStr(ids));
            list = this.listForStr(patientList);
        }

        return list;
    }

    /**
     * 获取分组里全部患者
     */
    private Set<Long> getAllGroupPatient(String groupIds) {
        Set<Long> patientSet = new HashSet<>();
        List<Long> ids = StringUtil.convertLongStr2List(groupIds, ",");
        if (!ids.isEmpty()) {
            List<Long> patientIds = this.drPatientGroupDetailDao.getPatientIdsByGroupIds(ids);
            patientSet.addAll(patientIds);
        }
        return patientSet;
    }

    private String listForStr(Collection<?> list) {
        StringBuilder sb = new StringBuilder();
        for (Object obj : list) {
            if (obj instanceof String) {
                sb.append(((String) obj).replace(",", ""));
            } else {
                sb.append(obj);
            }
            sb.append(",");
        }
        return sb.length() > 0 ? sb.substring(0, sb.length() - 1) : "";
    }

    private String getPatientNames(Long doctorId, String patientIds) {

        StringBuilder sb = new StringBuilder();
        Map<Long, String> patientMap = new HashMap<>();
        List<Long> ids = StringUtil.convertLongStr2List(patientIds, ",");
        List<Patient> patientList = this.patientDao.findAllPatientByIds(ids);
        for (Patient patient : patientList) {
            patientMap.put(patient.getId(), PatientUtil.getPatientName(patient, null).replace(",", ""));
        }

        List<DrPatientRemarkname> remarknameList = this.drPatientRemarkNameService.getRemarkInfoByPatientIds(doctorId, ids);
        // 替换成备注名
        Optional.ofNullable(remarknameList)
                .orElse(Lists.newArrayList())
                .stream()
                .filter(drPatientRemarkname -> !StringUtils.isBlank(drPatientRemarkname.getRemarkName()))
                .forEach(drPatientRemarkname -> patientMap.put(drPatientRemarkname.getPatientId(), drPatientRemarkname.getRemarkName()
                                                                                                                      .replace(",", "")));
        ids.forEach(id -> {
            sb.append(patientMap.get(id));
            sb.append(",");
        });

        return sb.length() > 0 ? sb.substring(0, sb.length() - 1) : "";
    }

    /**
     * 获取收件人信息
     */
    private String getMsgRecipients(Integer receiveType, String groupNames, String patientNames) {
        // 全部患者显示
        if (receiveType == ReceiveInfo.ALL) {
            return "所有患者";
        }
        // 组发送显示
        else if (receiveType == ReceiveInfo.GROUP || receiveType == ReceiveInfo.GROUP_REVERSE) {
            return groupNames;
        }
        // 自定义患者显示
        else if (receiveType == ReceiveInfo.DEFINED) {
            return patientNames;

        } else {
            return "";
        }

    }

}
